package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.utils.AssertUtils;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration;
import org.springframework.stereotype.Service;

import java.util.List;

import static com.tianji.learning.enums.LessonStatus.*;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author yuqing
 * @since 2025-03-22
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {
    private final ILearningLessonService lessonService;
    private final CourseClient courseClient;
    private final LearningRecordDelayTaskHandler taskHandler;


    /*
     * 提交学习记录
     * */
    @Override
    public void submitLearningRecord(LearningRecordFormDTO formDTO) {
        //处理学习记录信息
        boolean firstFinished = formDTO.getSectionType() == SectionType.VIDEO ? videoLearningRecord(formDTO) : examLearningRecord(formDTO);
        if (!firstFinished && formDTO.getDuration() == -1) {
            return;
        }
        //2.处理课表信息
        handleLearningLesson(formDTO, firstFinished);
    }

    private void handleLearningLesson(LearningRecordFormDTO formDTO, boolean firstFinished) {
        //1.查询课表信息并判断是否存在
        LearningLesson lesson = lessonService.getById(formDTO.getLessonId());
        if (ObjectUtils.isEmpty(lesson)) {
            log.error("查询课表信息失败，{}", formDTO);
        }
        //根据课表查询课程信息
        boolean allFinished = false;
        if (firstFinished) {
            CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
            AssertUtils.isNotNull(courseInfo, "课程信息不存在，无法更新数据");
            //2.判断是否是第一次完成，更新不同的课表信息
            allFinished = lesson.getLearnedSections() + 1 >= courseInfo.getSectionNum();
        }
        boolean updateResult = this.lessonService.lambdaUpdate()
                .set(LearningLesson::getLatestSectionId, formDTO.getSectionId()) // 更新最新学过的小节ID
                .set(LearningLesson::getLatestLearnTime, formDTO.getCommitTime()) // 更新最新学过的时间
                //.set(firstFinished, LearningLesson::getLearnedSections, lesson.getLearnedSections() + 1)
                .setSql(firstFinished, "learned_sections = learned_sections + 1")  // 更新已学习小节数+1 update table set {...} where ...
                .set(allFinished, LearningLesson::getStatus, FINISHED) // 更新课表状态为已学完
                .set(lesson.getStatus() == NOT_BEGIN, LearningLesson::getStatus, LEARNING)
                .eq(LearningLesson::getId, lesson.getId())
                .update();
        if (!updateResult) {
            log.error("更新课表信息失败，{}", formDTO);
        }
        taskHandler.cleanLearningRecordFromCache(formDTO.getLessonId(), formDTO.getSectionId());

    }

    /*
     * 提交考试学习记录逻辑*/
    private boolean examLearningRecord(LearningRecordFormDTO formDTO) {
        //1。对象复制
        LearningRecord record = BeanUtil.copyProperties(formDTO, LearningRecord.class);
        //2.填充缺失信息
        record.setUserId(UserContext.getUser());
        record.setFinished(true);
        record.setFinishTime(formDTO.getCommitTime());
        //3.保存学习记录
        boolean save = save(record);
        if (!save) {
            log.error("保存学习记录失败，{}", formDTO);
        }
        return true;
    }

    /*
     * 提交视频学习记录逻辑*/
    private boolean videoLearningRecord(LearningRecordFormDTO formDTO) {
        //1.针对某一小节查询旧的学习记录
        LearningRecord oldRecord = queryOldRecord(formDTO);

        //2.判断学习记录是否存在，
        if (ObjectUtils.isEmpty(oldRecord)) {
            //如果不存在，新增学习记录
            LearningRecord record = BeanUtil.toBean(formDTO, LearningRecord.class);
            record.setUserId(UserContext.getUser());
            boolean save = save(record);
            if (!save) {
                log.error("保存学习记录失败，{}", formDTO);
            }
            return false;
        }
        //3.如果存在，更新学习记录
        //3.1判断是否是第一次学完（进度超过总时长一半，就得状态是未学完）
        boolean firstFinished = !oldRecord.getFinished() && formDTO.getMoment() << 1 >= formDTO.getDuration();
        //如果是非第一次学完，将学习记录暂存至redis，并且提交一个延迟任务

        if (!firstFinished) {
            LearningRecord learningRecord = new LearningRecord();
            learningRecord.setLessonId(formDTO.getLessonId());
            learningRecord.setSectionId(formDTO.getSectionId());
            learningRecord.setId(oldRecord.getId());
            learningRecord.setMoment(formDTO.getMoment());
            learningRecord.setFinished(oldRecord.getFinished());
            taskHandler.addLearningRecordDelayCheckTask(learningRecord);
            formDTO.setDuration(-1);
            return false;

        }
        //更新学习记录（一定更新：moment，如果是第一次学完，还要更新finished为true，finished_time）
        boolean updateResult = this.lambdaUpdate()
                .set(LearningRecord::getMoment, formDTO.getMoment())
                .set(LearningRecord::getFinished, true)
                .set(LearningRecord::getFinishTime, formDTO.getCommitTime())
                .eq(LearningRecord::getId, oldRecord.getId())
                .update();
        if (!updateResult) {
            log.error("更新学习记录失败，{}", formDTO);
        }
        taskHandler.cleanLearningRecordFromCache(formDTO.getLessonId(), formDTO.getSectionId());
        return true;
    }

    /*
     * 查询旧的学习记录*/
    private LearningRecord queryOldRecord(LearningRecordFormDTO formDTO) {
        //1.先查询redis缓存
        LearningRecord oldRecord = taskHandler.readLearningRecordFromCache(formDTO.getSectionId(), formDTO.getLessonId());
        //2.判读是否存在,如果redis中存在，直接返回
        if (ObjectUtils.isNotEmpty(oldRecord)) {
            return oldRecord;
        }
        //3.如果不存在，查询数据库，并写入redis缓存
        oldRecord = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, formDTO.getLessonId())
                .eq(LearningRecord::getSectionId, formDTO.getSectionId())
                .one();
        if (ObjectUtils.isEmpty(oldRecord)) {
            return null; // 不能抛异常，要作为调用者后续代码逻辑的判断依据
        }
        taskHandler.writeLearningRecordFromCache(oldRecord);
        return oldRecord;
    }


    /*
     * 查询学习记录
     * */
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        //1.获取用户id
        Long user = UserContext.getUser();
        //2.根据用户id和课程id查询课表
        LearningLesson lesson = lessonService.lambdaQuery().eq(LearningLesson::getUserId, user).eq(LearningLesson::getCourseId, courseId).one();
        if (lesson == null) {
            return null;
        }
        //3.根据课表id查询学习记录
        List<LearningRecord> list = this.lambdaQuery().eq(LearningRecord::getLessonId, lesson.getId()).list();
        //4.组装数据返回
        LearningLessonDTO learningLessonDTO = new LearningLessonDTO();
        learningLessonDTO.setId(lesson.getId());
        learningLessonDTO.setLatestSectionId(lesson.getLatestSectionId());
        learningLessonDTO.setRecords(BeanUtils.copyList(list, LearningRecordDTO.class));
        return learningLessonDTO;
    }
}
